/*
 * @Author: czy
 * @Date: 2021-05-30 22:56:24
 * @LastEditTime: 2021-06-04 16:44:07
 */
#include "string.h"
#include "stdarg.h"

#include "vector.h"
#include "malloc.h"

void *__POINTER_SIZE__;

static void init(void *vector)
{
    Vector *v = (Vector *)vector;
    if (v->type == NOTINIT)
    {
        int num = INIT_LENGTH;
        if (*(v->info.lengthinfo) != '\0')
        {
            num = str2int(v->info.lengthinfo);
        }
        v->allocated = ((((num > INIT_LENGTH ? num : INIT_LENGTH) - 1) / 4) + 1) * 4;
        deblank(v->info.typeinfo);
        if (strcmp(v->info.typeinfo, "void *") == 0)
        {
            v->type = UNKNOWN;
            v->size = ((v->info.size1 - 1) / sizeof(int) + 1) * sizeof(int);
        }
        else if (strcmp(v->info.typeinfo, "char *") == 0)
        {
            v->type = STRING;
            v->size = ((v->info.size1 - 1) / sizeof(int) + 1) * sizeof(int);
        }
        else if (find(v->info.typeinfo, '*'))
        {
            v->type = POINTER;
            v->size = ((v->info.size1 - 1) / sizeof(int) + 1) * sizeof(int);
        }
        else
        {
            v->type = RAWDATA;
            v->size = ((v->info.size2 - 1) / sizeof(int) + 1) * sizeof(int);
        }
    }
    if (v->length == 0)
    {
        if (v->type == RAWDATA)
        {
            v->data = (void **)calloc(v->allocated, v->size);
        }
        else
        {
            v->data = (void **)malloc(v->allocated * sizeof(void *));
        }
    }
}

void vector_resize(void *vector)
{
    Vector *v = (Vector *)vector;
    int flag = 0;
    if (v->length >= v->allocated)
    {
        v->allocated *= 2;
        flag = 1;
    }
    else if (v->length < v->allocated / 2 && v->allocated > INIT_LENGTH)
    {
        v->allocated /= 2;
        flag = 1;
    }
    if (flag == 1)
    {
        void **data = (void **)malloc(v->allocated * v->size);
        memcpy((void *)data, (void *)(v->data), v->length * v->size);
        free((unsigned long)(v->data));
        v->data = data;
    }
}

int vector_set(void *vector, int index, ...)
{
    Vector *v = (Vector *)vector;
    init(v);
    if (index < 0)
    {
        index += v->length;
    }
    if (index < 0 || index >= v->length)
    {
        return FALSE;
    }
    va_list args;
    va_start(args, index);
    if (v->type != RAWDATA)
    {
        void *data = va_arg(args, void *);
        int size;
        switch (v->type)
        {
        case UNKNOWN:
            size = va_arg(args, int);
            break;
        case STRING:
            size = strlen((char *)data) + 1;
            break;
        case POINTER:
            size = v->size;
            break;
        default:
            break;
        }
        va_end(args);
        void *item = (void *)malloc(size);
        memcpy(item, data, size);
        (v->data)[index] = item;
    }
    else
    {
        char *temp = (char *)v->data;
        memcpy(&((temp)[index * v->size]), va_arg_by_size(args, v->size), v->size);
        va_end(args);
    }
    return TRUE;
}

void vector_append(void *vector, ...)
{
    Vector *v = (Vector *)vector;
    init(v);
    va_list args;
    va_start(args, vector);
    if (v->type != RAWDATA)
    {
        void *data = va_arg(args, void *);
        int size;
        switch (v->type)
        {
        case UNKNOWN:
            size = va_arg(args, int);
            break;
        case STRING:
            size = strlen((char *)data) + 1;
            break;
        case POINTER:
            size = v->size;
            break;
        default:
            break;
        }
        va_end(args);
        void *item = (void *)malloc(size);
        memcpy(item, data, size);
        (v->data)[v->length] = item;
    }
    else
    {
        char *temp = (char *)v->data;
        memcpy(&(temp[v->length * v->size]), va_arg_by_size(args, v->size), v->size);
        va_end(args);
    }
    v->length++;
    v->resize(vector);
}

void *vector_pop(void *vector, void *value, ...)
{
    Vector *v = (Vector *)vector;
    init(v);
    if (v->length == 0)
    {
        return NULL;
    }
    int size;
    va_list args;
    if (v->type != RAWDATA)
    {
        switch (v->type)
        {
        case UNKNOWN:
            va_start(args, value);
            size = va_arg(args, int);
            va_end(args);
            break;
        case STRING:
            size = strlen((char *)v->data[v->length - 1]) + 1;
            break;
        case POINTER:
            size = v->size;
            break;
        default:
            break;
        }
        void *data = (v->data)[v->length - 1];
        memcpy(value, (void *)data, size);
        free((unsigned long)data);
    }
    else
    {
        char *temp = (char *)v->data;
        memcpy(value, &((temp)[(v->length - 1) * v->size]), v->size);
    }
    v->length--;
    v->resize(vector);
    return value;
}

int vector_insert(void *vector, int index, ...)
{
    Vector *v = (Vector *)vector;
    init(v);
    if (index < 0)
    {
        index += v->length;
    }
    if (index < 0 || index > v->length)
    {
        return FALSE;
    }
    va_list args;
    va_start(args, index);
    if (v->type != RAWDATA)
    {
        void *data = va_arg(args, void *);
        int size;
        switch (v->type)
        {
        case UNKNOWN:
            size = va_arg(args, int);
            break;
        case STRING:
            size = strlen((char *)data) + 1;
            break;
        case POINTER:
            size = v->size;
            break;
        default:
            break;
        }
        va_end(args);
        void *item = (void *)malloc(size);
        memcpy(item, data, size);
        for (int i = v->length - 1; i >= index; i--)
        {
            (v->data)[i + 1] = (v->data)[i];
        }
        (v->data)[index] = item;
    }
    else
    {
        char *temp = (char *)v->data;
        for (int i = v->length - 1; i >= index; i--)
        {
            memcpy(&((temp)[(i + 1) * v->size]), &((temp)[i * v->size]), v->size);
        }
        memcpy(&((temp)[index * v->size]), va_arg_by_size(args, v->size), v->size);
        va_end(args);
    }
    v->length++;
    v->resize(vector);
    return TRUE;
}

int vector_remove(void *vector, int index)
{
    Vector *v = (Vector *)vector;
    init(v);
    if (index < 0)
    {
        index += v->length;
    }
    if (index < 0 || index >= v->length)
    {
        return FALSE;
    }
    if (v->type != RAWDATA)
    {
        free((unsigned long)(v->data)[index]);
        for (int i = index; i < v->length - 1; i++)
        {
            (v->data)[i] = (v->data)[i + 1];
        }
    }
    else
    {
        char *temp = (char *)v->data;
        for (int i = index; i < v->length - 1; i++)
        {
            memcpy(&((temp)[i * v->size]), &((temp)[(i + 1) * v->size]), v->size);
        }
    }
    v->length--;
    v->resize(vector);
    return TRUE;
}

void *vector_get(void *vector, int index)
{
    Vector *v = (Vector *)vector;
    init(v);
    if (index < 0)
    {
        index += v->length;
    }
    if (index < 0 || index >= v->length)
    {
        return NULL;
    }
    if (v->type != RAWDATA)
    {
        return v->data[index];
    }
    else
    {
        char *temp = (char *)v->data;
        return &(temp[index * v->size]);
    }
}

void vector_clear(void *vector)
{
    Vector *v = (Vector *)vector;
    init(v);
    if (v->type != RAWDATA)
    {
        for (int i = 0; i < v->length; i++)
        {
            free((unsigned long)(v->data)[i]);
        }
    }
    free((unsigned long)(v->data));
    v->allocated = INIT_LENGTH;
    v->length = 0;
}
